home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs2.zip / RNEWS / history.c < prev    next >
C/C++ Source or Header  |  1992-11-13  |  14KB  |  423 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    h i s t o r y . c                                               */
  3. /*                                                                    */
  4. /*    News history file maintenance for UUPC/extended.                */
  5. /*                                                                    */
  6. /*    Written by Mike Lipsie                                          */
  7. /*                                                                    */
  8. /*    The history file                                                */
  9. /*                                                                    */
  10. /*    This file describes and implements the history file.            */
  11. /*                                                                    */
  12. /*    The history file is [newsdir]/history and is "added" to by      */
  13. /*    rnews.  It is "pruned" by expire and is used by rnews (to       */
  14. /*    check that the article has not arrived before), expire (to      */
  15. /*    find all copies of the article), and rn (to mark as read all    */
  16. /*    copies of an article.)                                          */
  17. /*                                                                    */
  18. /*    The history file is entirely ASCII.                             */
  19. /*                                                                    */
  20. /*    The first line is a code that identifies the version level      */
  21. /*    (so that future versions can automatically upgrade.)  For       */
  22. /*    version one that code is "ZIP1".                                */
  23. /*                                                                    */
  24. /*    Every line (except the version line) is the record of a         */
  25. /*    single incoming article.  That line is exactly as described     */
  26. /*    without added spaces or other punctuation.  The first field     */
  27. /*    is the Message-ID including (or added if they don't exist),     */
  28. /*    the "<" and ">", a space, the date received (dd/mm/yyyy with    */
  29. /*    days and months being zero filled if necessary), a space,       */
  30. /*    and the "destination" information.                              */
  31. /*                                                                    */
  32. /*    The destination information is the Newsgroups:  with a colon    */
  33. /*    and the article number for each group added (article number     */
  34. /*    zero is used for newsgroups not accepted.)                      */
  35. /*                                                                    */
  36. /*    For example, if article <123@pyramid> was received on 3 Jan     */
  37. /*    1992 and was posted to ba.food, ba.transportation, and          */
  38. /*    soc.singles and ended up in article 4334, 1234, and 56789       */
  39. /*    (respectively), the record would be                             */
  40. /*                                                                    */
  41. /*    <123@pyramid> 03/01/1992                                        */
  42. /*    ba.food:4334,ba.transportation:1234,soc.singles:56789           */
  43. /*                                                                    */
  44. /*    To speed access into the history file there is a parallel       */
  45. /*    file history.ndx which contains information where each day's    */
  46. /*    worth of history records begins.  The first line is a           */
  47. /*    version number and must be the same as that of the history      */
  48. /*    file.  All the other records are the 10 character date code,    */
  49. /*    a space, and a ten digit location code (right justified,        */
  50. /*    zero or blank filled.)  The location code is the byte           */
  51. /*    displacement into the history file of the first record with     */
  52. /*    that date code.                                                 */
  53. /*--------------------------------------------------------------------*/
  54.  
  55.  
  56. /*--------------------------------------------------------------------*/
  57. /*                        System include files                        */
  58. /*--------------------------------------------------------------------*/
  59.  
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <time.h>
  64. #include <fcntl.h>
  65. #include <io.h>
  66. #include <sys/types.h>
  67. #include <sys/stat.h>
  68.  
  69. /*--------------------------------------------------------------------*/
  70. /*                    UUPC/extended include files                     */
  71. /*--------------------------------------------------------------------*/
  72.  
  73. #include "lib.h"
  74. #include "hlib.h"
  75. #include "timestmp.h"
  76. #include "active.h"
  77. #include "history.h"
  78.  
  79. /*  These variables are used to improve the performance of checking
  80.  *  for previous existance of an article.
  81.  *
  82.  *  The basic theory of how this feature works is that a file
  83.  *  (history.dbm) is built with enough information (it is hoped)
  84.  *  to eliminate 99% (well, most) of the non matching message IDs.
  85.  *  A check is made when a match is made confiming that the match
  86.  *  is real.  Since most articles are not "re-sends" (all if you
  87.  *  have only one feed) this won't impose a large overhead.
  88.  *
  89.  *  The information that is used to eliminate unnecessary checks into
  90.  *  the history file for duplicate messageIDs is the first ten
  91.  *  characters of the message ID (not including the leading "<"),
  92.  *  the number of characters in the full ID (including the "<" and ">"),
  93.  *  a checksum of the full ID (also including the "<" and ">"), and
  94.  *  the location in the history file of the full ID.
  95.  *
  96.  *  Additionally, an array of MAXbuf (currently 8) buffers of history.dbm
  97.  *  are maintained in memory to avoid disk I/O.
  98.  *
  99.  */
  100.  
  101. int cur_buff = 0;
  102. int cur_off  = 0;
  103. #define MAXbuf 8
  104.  
  105. char *hb[MAXbuf];
  106. int hb_blk[MAXbuf];
  107.  
  108. extern FILE *hfile;
  109.  
  110. FILE *hdbm_file = NULL;
  111.  
  112. struct perf_elem {
  113.    char IDpart[10];  /* The first 10 characters (after the "<") of the message-ID */
  114.    char cksum;       /* Checksum of the entire ID (including <>) */
  115.    char IDlen;       /* Number of characters in the ID (including <>) */
  116.    long where;       /* ftell() in file of actual record */
  117. };
  118.  
  119.  
  120. /*--------------------------------------------------------------------*/
  121. /*    h i s t o r y _ e x i s t s                                     */
  122. /*                                                                    */
  123. /*    Determine if the history file exists and is a file (instead     */
  124. /*    of a directory).                                                */
  125. /*--------------------------------------------------------------------*/
  126.  
  127. boolean history_exists( void )
  128. {
  129.    char hfile_name[FILENAME_MAX];
  130.    struct stat buff;
  131.  
  132.    mkfilename(hfile_name, E_newsdir, "history");
  133.  
  134.    if ((stat(hfile_name, &buff) == 0) && buff.st_mode & S_IFREG)
  135.       return TRUE;
  136.    else
  137.       return FALSE;
  138.  
  139. } /* history_exists */
  140.  
  141.  
  142. /*--------------------------------------------------------------------*/
  143. /*    o p e n _ h i s t o r y                                         */
  144. /*                                                                    */
  145. /*    Open the history file and verify that it is of the correct      */
  146. /*    version.  If any error occurs, NULL is returned.                */
  147. /*--------------------------------------------------------------------*/
  148.  
  149. #ifdef __TURBOC__
  150. #pragma argsused
  151. #endif
  152.  
  153. FILE *open_history(char *history_date)
  154. {
  155.  
  156. #ifdef NEXT_RELEASE_MAYBE
  157.    char hfile_name[FILENAME_MAX];
  158.    FILE *hfile;
  159.    FILE *index_file;
  160.    char buff[BUFSIZ];
  161.  
  162.    mkfilename(hfile_name, newsdir, "history");
  163.    hfile = fopen(hfile_name, "a+b");
  164.    if (hfile == NULL) {
  165.       printmsg(0,"Unable to open history file");
  166.       return hfile;
  167.    }
  168.    fseek(hfile, 0L, SEEK_SET);
  169.    fgets(buff, sizeof(buff), hfile);
  170.    buff[strlen(buff)-1] = '\0';
  171.    if (buff[strlen(buff)-1] == '\r') buff[strlen(buff)-1] = '\0';
  172.    if ((strlen(buff)) != strlen(H_VERSION)) {
  173.       printmsg(0, "History version incorrect");
  174.       return NULL;
  175.    }
  176.    if (!equal(buff, H_VERSION)) {
  177.       printmsg(0, "History version incorrect");
  178.       return NULL;
  179.    }
  180.  
  181.  
  182.    fseek(hfile, 0L, SEEK_END);      /* I know it is unnecessary */
  183.  
  184.    /* Now the index file */
  185.    strcat(hfile_name, ".ndx");
  186.    index_file = fopen(hfile_name, "a+b");
  187.    if (index_file == NULL) {
  188.       printmsg(0,"Unable to open history file index");
  189.    }
  190.    fseek(index_file, 0L, SEEK_SET);
  191.    fgets(buff, sizeof(buff), index_file);
  192.    buff[strlen(buff)-1] = '\0';
  193.    if (buff[strlen(buff)-1] == '\r') buff[strlen(buff)-1] = '\0';
  194.    if ((strlen(buff)) != strlen(H_VERSION)) {
  195.       printmsg(0, "History index version incorrect");
  196.    }
  197.    if (!equal(buff, H_VERSION)) {
  198.       printmsg(0, "History index version incorrect");
  199.    }
  200.    fseek(index_file, -21L, SEEK_END);
  201.    fgets(buff, 25, index_file);
  202.    if (strncmp(history_date, buff, strlen(history_date)) != 0) {
  203.       fseek(index_file, 0L, SEEK_END);
  204.       sprintf(buff, "%s %9.9ld\n", history_date, ftell(hfile));
  205.       fwrite(buff, sizeof(char), strlen(buff), index_file);
  206.    }
  207.    fclose(index_file);
  208.    #else
  209.    hfile = NULL;
  210. #endif
  211.  
  212.    return NULL;
  213.  
  214. }
  215.  
  216.  
  217.  
  218. /*
  219.    Create a history file.
  220. */
  221.  
  222. FILE *create_history(char *history_date) {
  223.  
  224. char hfile_name[FILENAME_MAX];
  225. FILE *hfile;
  226. FILE *index_file;
  227. char buff[BUFSIZ];
  228.  
  229. mkfilename(hfile_name, E_newsdir, "history");
  230. hfile = fopen(hfile_name, "wb");
  231. if (hfile == NULL) {
  232.    printmsg(0, "Unable to create history file");
  233.    return hfile;
  234. }
  235.  
  236. strcpy(buff, H_VERSION);
  237. strcat(buff, "\n");
  238. fwrite(buff, sizeof(char), strlen(buff), hfile);
  239.  
  240. strcat(hfile_name, ".ndx");
  241. index_file = fopen(hfile_name, "wb");
  242. fwrite(buff, sizeof(char), strlen(buff), index_file);
  243. sprintf(buff, "%s %9.9ld\n", history_date, ftell(hfile));
  244. fwrite(buff, sizeof(char), strlen(buff), index_file);
  245. fclose(index_file);
  246.  
  247. return hfile;
  248. }
  249.  
  250.  
  251.  
  252. void init_history_dbm(void) {
  253.  
  254. #ifdef NEXT_RELEASE_MAYBE
  255. int not_eof;
  256. char *t;
  257. long l;
  258. int i;
  259. int j;
  260.  
  261. int cur_block;
  262.  
  263. struct perf_elem *p;
  264.  
  265. char dbm_name[FILENAME_MAX];
  266. char hbuf[BUFSIZ];         /* Buffer for each history file record */
  267.  
  268.    mkfilename(dbm_name, tempdir, "history.dbm");
  269.    hdbm_file = fopen(dbm_name, "w+b");
  270.    if (hdbm_file == NULL) {
  271.       printmsg(0,"Unable to create history dbm file");
  272.       exit(5);
  273.    }
  274.  
  275.    for (i = 0; i < MAXbuf; i++) {
  276.       hb[i] = malloc(BUFSIZ);
  277.       checkref(hb[i]);
  278.       hb_blk[i] = -1;
  279.    }
  280.  
  281.    cur_block = 0;
  282.    cur_buff = 0;
  283.    cur_off = 0;
  284.  
  285.    /* Now build the file */
  286.    fseek(hfile, (long)(strlen(H_VERSION)+1), SEEK_SET);  /* Back to the beginning */
  287.    not_eof = TRUE;
  288.    while (not_eof) {
  289.       l = ftell(hfile);
  290.       t = fgets(hbuf, BUFSIZ, hfile);
  291.       if (t == NULL) {
  292.          not_eof = FALSE;
  293.       } else {
  294.          if (cur_off >= (BUFSIZ/sizeof(struct perf_elem))) {
  295.             fwrite(hb[cur_buff], sizeof(char), BUFSIZ, hdbm_file);
  296.             hb_blk[cur_buff] = cur_block++;
  297.             cur_off = 0;
  298.             if (++cur_buff >= MAXbuf) {
  299.                cur_buff = 0;
  300.             }
  301.             }
  302.          p = (struct perf_elem *)hb[cur_buff];
  303.          p += cur_off++;
  304.  
  305.          t = strchr(hbuf, ' ');
  306.          if (t == NULL) t = hbuf;
  307.          *t = '\0';
  308.  
  309.          p->where = l;
  310.          p->IDlen = strlen(t);
  311.          j = 0;
  312.          for (i = p->IDlen-1; i >= 0; i--) {
  313.             j = j + t[i];
  314.          }
  315.          p->cksum = (char)j;
  316.             strncpy(p->IDpart, &(t[1]), sizeof(p->IDpart));
  317.       }
  318.    } /* while not eof */
  319.  
  320.    /* Dump out last (probably partial) block */
  321.    if (cur_off < (BUFSIZ/sizeof(struct perf_elem))) {
  322.       p = (struct perf_elem *)hb[cur_buff];
  323.       p += cur_off;
  324.       strnset((char *)p, '\0', (&hb[cur_buff][BUFSIZ] - &(char *)p));
  325.    }
  326.    fwrite(hb[cur_buff], sizeof(char), BUFSIZ, hdbm_file);
  327.    hb_blk[cur_buff] = cur_block;
  328. #endif
  329.  
  330.    return;
  331. }
  332.  
  333. /*--------------------------------------------------------------------*/
  334. /*    i s _ i n _ h i s t o r y                                       */
  335. /*                                                                    */
  336. /*    Check whether messageID is already in the history file.         */
  337. /*--------------------------------------------------------------------*/
  338.  
  339. boolean is_in_history(FILE *hfile, char *messageID)
  340. {
  341.  
  342. #ifdef NEXT_RELEASE_MAYBE
  343.    int this_blk;
  344.  
  345.    struct perf_elem *p;
  346.  
  347.    if (hdbm_file == NULL) {
  348.       /* Initialize */
  349.       init_history_dbm();
  350.    }
  351.  
  352.    /* First check the blocks in memory */
  353.    this_blk = 0;
  354.    cur_off = 0;
  355.  
  356.    while (this_blk < MAXbuf) {
  357.       if (cur_off >= (BUFSIZ/sizeof(struct perf_elem))) {
  358.          cur_off = 0;
  359.          if (++this_blk >= MAXbuf) {
  360.             break;
  361.          }
  362.          if (hb_blk[this_blk] == -1) break;
  363.       }
  364.       p = (struct perf_elem *)hb[this_blk];
  365.       p += cur_off++;
  366.  
  367.       if (check_out_this_one(messageID, p)) {
  368.          return TRUE;
  369.        }
  370.    }
  371.  
  372.    /* Now check out the rest of the file */
  373. #else
  374.  
  375. /*--------------------------------------------------------------------*/
  376. /*        Slow but true version extracted from rnews.c by ahd         */
  377. /*--------------------------------------------------------------------*/
  378.  
  379.    boolean not_eof = TRUE;
  380.  
  381.    fseek(hfile, (long)(strlen(H_VERSION)+1), SEEK_SET);
  382.                                           /* Back to the beginning */
  383.  
  384. /*--------------------------------------------------------------------*/
  385. /*            Scan the entire disk file from the beginning            */
  386. /*--------------------------------------------------------------------*/
  387.  
  388.    while (not_eof)
  389.    {
  390.       char hist_record[BUFSIZ];
  391.       char *gc_ptr = fgets(hist_record, sizeof(hist_record), hfile);
  392.  
  393.       if (gc_ptr == NULL)
  394.          not_eof = FALSE;
  395.       else {
  396.          gc_ptr = strchr(hist_record, ' ');
  397.          if (gc_ptr == NULL)
  398.             gc_ptr = hist_record;
  399.          *gc_ptr = '\0';
  400.          printmsg(9, "rnews:Comparing to history:%s", hist_record);
  401.          if (equal(hist_record, messageID))
  402.             return TRUE;
  403.       } /* else */
  404.     } /* while (not_eof) */
  405.  
  406. #endif
  407.  
  408.    return FALSE;
  409. } /* is_in_history */
  410.  
  411.  
  412. #ifdef NEXT_RELEASE_MAYBE
  413.  
  414. int check_out_this_one(char *m_id, struct perf_elem *p)
  415. {
  416.  
  417.    printf("check_out_this_one called \n");
  418.    return TRUE;
  419.  
  420. }
  421.  
  422. #endif
  423.